package cn.initcap;

import cn.initcap.authentication.FormAuthenticationConfig;
import cn.initcap.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import cn.initcap.authorize.AuthorizeConfigManager;
import cn.initcap.properties.SecurityProperties;
import cn.initcap.validate.ValidateCodeSecurityConfig;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.social.security.SpringSocialConfigurer;

/**
 * @author initcap
 * @date Created in 2018/5/17 PM5:27.
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

    @Autowired
    private ValidateCodeSecurityConfig validateCodeSecurityConfig;

    @Autowired
    private SpringSocialConfigurer initcapSocialSecurityConfig;

    @Autowired
    private AuthorizeConfigManager authorizeConfigManager;

    @Autowired
    private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;

    @Autowired
    private InvalidSessionStrategy invalidSessionStrategy;

    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    private FormAuthenticationConfig formAuthenticationConfig;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        //配置数据库（demo的application-dev.yml中）
        tokenRepository.setDataSource(dataSource);
        //项目启动时会创建数据库 tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

    /**
     * 认证配置
     *
     * @param http 安全请求
     * @throws Exception 异常
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        formAuthenticationConfig.configure(http);

        http.apply(validateCodeSecurityConfig)
                .and()
                .apply(smsCodeAuthenticationSecurityConfig)
                .and()
                .apply(initcapSocialSecurityConfig)
                .and()
                //管理session
                .sessionManagement()
                .invalidSessionStrategy(invalidSessionStrategy)
                //这里设置同一个用户的session最大为1，也就是后者踢前者
                .maximumSessions(securityProperties.getWeb().getSession().getMaximumSessions())
                //针对踢的行为作一个记录
                .expiredSessionStrategy(sessionInformationExpiredStrategy)
                //设置的值为true时是后者不可以登录，false为后者踢前者
                .maxSessionsPreventsLogin(securityProperties.getWeb().getSession().isMaxSessionsPreventsLogin())
                .and()
                .and()
                //记住我配置，如果想在'记住我'登录时记录日志，可以注册一个InteractiveAuthenticationSuccessEvent事件的监听器
                .rememberMe()
                .tokenRepository(persistentTokenRepository())
                //配置记住时间
                .tokenValiditySeconds(securityProperties.getWeb().getRememberMeSeconds())
                .userDetailsService(userDetailsService)
                .and()
                .logout()
                .logoutUrl(securityProperties.getWeb().getSignOutUrl())
                .logoutSuccessHandler(logoutSuccessHandler)
                .deleteCookies("JSESSIONID")
                .and()
                //关闭跨站请求伪造防护功能
                .csrf().disable();

        //自定义配置页面访问权限
        authorizeConfigManager.config(http.authorizeRequests());
    }


}
